package utils;

import gamecontrol.CurrentBoard;
import java.util.*;

/**
 *
 * @author quique
 */
public class Timer implements Runnable {
    private Date init,stop;
    private Thread thread = null;
    private int duration = 0;
    private int durationPrevious = 0;
    private int interval = 1000;
    private boolean repetition = false;
    private boolean inExec = false;
    private ITimer handler = null;

    public Timer() {
    }
    
    /**
     * Constructor
     * @param time
     */
    Timer( int time ) { 
        setDuration( time ); 
    }
    

    /**
     * Constructor
     * @param Handler
     */
    Timer( ITimer Handler ) { 
        setHandler( Handler ); 
    }
    
    /**
     * Contrutctor
     * @param time
     * @param Handler
     */
    Timer( int time,ITimer Handler ) {
        setDuration( time );
        setHandler( Handler );
    }
     
    /**
     * Establish the number of seconds that the clock has.
     * @param time
     */
    public void setDuration( int time ) { 
        duration = time; 
    }
    
    /**
     * Fix the object that must be notified of the events of timer
     * @param Handler
     */
    public void setHandler( ITimer Handler ) { 
        handler = Handler; 
    }
    
    /**
     * Fix the number of miliseconds between the timer pulses
     * @param Interval
     */
    public void setInterval( int Interval ) { 
        interval = Interval; 
    }
    

    /**
     * 
     * @return number of seconds that the clock has
     */
    public int getDuration() { 
        return( duration ); 
    }
 
    /**
     * 
     * @return
     */
    public ITimer getHandler() { 
        return( handler ); 
    }
    
    /**
     * 
     * @return the time in miliseconds that the clock controls.
     */
    public int getInterval() { 
        return( interval ); 
    }   
    
    /**
     * 
     * @return Number of seconds that passed since timer started
     */
    public int getElapsed() {
         return( calculateLapse( new Date() ) ); 
    }   
 
    /**
     * Reset the timer
     */
    public void resetDuration() { 
        duration = durationPrevious; 
    }   
    
    /**
     * Creation of a new thread to run the Timer. It initilizes with this to
     * run() method will be called inmediatily since the thread execution
     */
    public void start() {
        thread = new Thread( this );
        thread.start();
    }
 
    /**
     * Stops the clock
     */
    public void stop() {
        inExec = false;
        stop = new Date();
        if ( handler != null )
            handler.timerStopped( this );
    }
    
    /**
     * Starts the execution.
     */
    public void run() {
        inExec = true;
        durationPrevious = duration;
 
        //Starts the timer and notification to the outstanding classes
        init = new Date();
        if( handler != null )
            handler.timerStarted( this );
 
        while( inExec ){
            //wait the given interval time
            try {
                waits( interval );
            }
            catch( InterruptedException e ) {
                return;
            }
             
            //When the interval finishes, advice to the outstanding classes
            if( handler != null )
                handler.timerInterval( this );
            
            //how many time the timer last
            if( duration > 0 ){
                //check if the timer is death, for not death again 
                if( this.isDeath() ){
                    // if is death, propagation
                    if( handler != null )
                        handler.timerDeath( this );               
                    //if user want a repetion, reboot the Timer
                    if( repetition ){
                        inExec = true;
                        init = new Date();
                        if( handler != null )
                            handler.timerStarted( this );   
                    }
                    else{
                        inExec = false;
                    }
                }
            }
        }
    }    
    
    /**
     * 
     * @return
     */
    public boolean isRunning() { 
        return( inExec ); 
    }
    
    /**
     * 
     * @return
     */
    public boolean isStoped() { 
        return( !inExec ); 
    }
    
    /**
     * 
     * @return
     */
    public boolean isDeath() {
        int seconds = 0;
 
        //calculate the time interval that spends since the Timer started
        seconds = calculateLapse( new Date() );
 
        if( seconds >= duration ) 
            return( true );
        else
            return( false );
    }
          
    /**
     * 
     * @param current
     * @return
     */
    private int calculateLapse( Date current ) {
        Date dfinal;
        int  seconds = 0;
 
        if( inExec )
            dfinal = current;
        else
            dfinal = stop;
 
        seconds += ( dfinal.getHours() - init.getHours() ) * 3600;
        seconds += ( dfinal.getMinutes() - init.getMinutes() ) * 60;
        seconds += ( dfinal.getSeconds() - init.getSeconds() );
        return( seconds );
    }
    
    /**
     * Implements the waiting. The lapse of miliseconds is passed to the wait
     * method of the Thread.
     * This method is synchronized because if not a exception occured.
     * @param lapse time in miliseconds
     * @throws java.lang.InterruptedException
     */
    private synchronized void waits( int lapse ) 
        throws InterruptedException {
        this.wait( lapse );
        }   
    }
